home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #12 / Amiga Plus CD - 2002 - No. 12.iso / Tools / Development / qstat25b / template.c < prev   
C/C++ Source or Header  |  2002-11-18  |  25KB  |  1,061 lines

  1. /*
  2.  * qstat 2.5a
  3.  * by Steve Jankowski
  4.  * steve@qstat.org
  5.  * http://www.qstat.org
  6.  *
  7.  * Thanks to Per Hammer for the OS/2 patches (per@mindbend.demon.co.uk)
  8.  * Thanks to John Ross Hunt for the OpenVMS Alpha patches (bigboote@ais.net)
  9.  * Thanks to Scott MacFiggen for the quicksort code (smf@webmethods.com)
  10.  *
  11.  * Inspired by QuakePing by Len Norton
  12.  *
  13.  * Copyright 1996,1997,1998,1999 by Steve Jankowski
  14.  *
  15.  * Licensed under the Artistic License, see LICENSE.txt for license terms
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include <time.h>
  23.  
  24. #ifdef __hpux
  25. #include <sys/types.h>
  26. #include <netinet/in.h>
  27. #endif
  28. #ifdef _AIX
  29. #include <sys/types.h>
  30. #include <netinet/in.h>
  31. #endif
  32.  
  33. #include "qstat.h"
  34.  
  35. #ifdef _WIN32
  36. #define strcasecmp    stricmp
  37. #define strncasecmp    strnicmp
  38. #endif
  39.  
  40. #ifdef __hpux
  41. #define STATIC static
  42. #else
  43. #define STATIC
  44. #endif
  45.  
  46. /*
  47. #ifdef __cplusplus
  48. extern "C" {
  49. #endif
  50. #ifndef _AIX
  51. extern unsigned int ntohl(unsigned int n);
  52. #endif
  53. #ifdef __cplusplus
  54. }
  55. #endif
  56. */
  57.  
  58. extern int hostname_lookup;
  59. extern int get_player_info;
  60. extern int get_server_rules;
  61. extern int num_servers_total;
  62. extern int num_servers_timed_out;
  63. extern int num_servers_down;
  64. extern int num_players_total;
  65. extern int html_names;
  66. extern int hex_player_names;
  67. extern FILE *OF;        /* output file */
  68.  
  69. static char *server_template;
  70. static char *rule_template;
  71. static char *header_template;
  72. static char *trailer_template;
  73. static char *player_template;
  74.  
  75. static void display_server_var( struct qserver *server, int var);
  76. static void display_player_var( struct player *player, int var, struct qserver *server);
  77. static void display_rule_var( struct rule *rule, int var, struct qserver *server);
  78. static void display_generic_var( int var);
  79. static int parse_var( char *varname, int *varlen);
  80. static int read_template( char *filename, char **template_text);
  81. static void display_string( char *str);
  82. static int is_true( struct qserver *server, struct player *player,
  83.     struct rule *rule, char *expr);
  84.  
  85.  
  86. #define VARIABLE_CHAR '$'
  87.  
  88. static char *variable_option;
  89. static int if_skip;
  90. static int if_level;
  91. static int if_skip_save;
  92. static int if_level_save;
  93. int html_mode= 0;
  94. int clear_newlines_mode= 0;
  95. int rule_name_spaces= 0;
  96.  
  97. struct vardef {
  98.     char *var;
  99.     int varcode;
  100.     int options;
  101. };
  102.  
  103. #define NO_OPTIONS 0
  104. #define OPTIONS_OK 1
  105. #define EXPR       2
  106.  
  107. struct vardef variable_defs[] = {
  108. #define V_HOSTNAME    1
  109.     {"HOSTNAME", V_HOSTNAME, NO_OPTIONS },
  110. #define V_SERVERNAME    2
  111.     {"SERVERNAME", V_SERVERNAME, NO_OPTIONS },
  112. #define V_PING        3
  113.     {"PING", V_PING, NO_OPTIONS },
  114. #define V_PLAYERS    4
  115.     {"PLAYERS", V_PLAYERS, NO_OPTIONS | EXPR },
  116. #define V_MAXPLAYERS    5
  117.     {"MAXPLAYERS", V_MAXPLAYERS, NO_OPTIONS },
  118. #define V_MAP        6
  119.     {"MAP", V_MAP, NO_OPTIONS },
  120. #define V_GAME        7
  121.     {"GAME", V_GAME, NO_OPTIONS | EXPR },
  122. #define V_RETRIES    8
  123.     {"RETRIES", V_RETRIES, NO_OPTIONS },
  124. #define V_IPADDR    9
  125.     {"IPADDR", V_IPADDR, NO_OPTIONS },
  126. #define V_PORT        10
  127.     {"PORT", V_PORT, NO_OPTIONS },
  128. #define V_ARG        11
  129.     {"ARG", V_ARG, NO_OPTIONS },
  130. #define V_QSTATURL    12
  131.     {"QSTATURL", V_QSTATURL, NO_OPTIONS },
  132. #define V_QSTATVERSION    13
  133.     {"QSTATVERSION", V_QSTATVERSION, NO_OPTIONS },
  134. #define V_QSTATAUTHOR    14
  135.     {"QSTATAUTHOR", V_QSTATAUTHOR, NO_OPTIONS },
  136. #define V_QSTATAUTHOREMAIL    15
  137.     {"QSTATAUTHOREMAIL", V_QSTATAUTHOREMAIL, NO_OPTIONS },
  138. #define V_TYPE    16
  139.     {"TYPE", V_TYPE, NO_OPTIONS },
  140. #define V_RULE    17
  141.     {"RULE", V_RULE, OPTIONS_OK | EXPR },
  142. #define V_ALLRULES    18
  143.     {"ALLRULES", V_ALLRULES, NO_OPTIONS },
  144. #define V_PLAYERTEMPLATE    19
  145.     {"PLAYERTEMPLATE", V_PLAYERTEMPLATE, NO_OPTIONS },
  146. #define V_PLAYERNAME    20
  147.     {"PLAYERNAME", V_PLAYERNAME, NO_OPTIONS },
  148. #define V_FRAGS        21
  149.     {"FRAGS", V_FRAGS, NO_OPTIONS },
  150. #define V_PLAYERPING    22
  151.     {"PLAYERPING", V_PLAYERPING, NO_OPTIONS },
  152. #define V_CONNECTTIME    23
  153.     {"CONNECTTIME", V_CONNECTTIME, NO_OPTIONS },
  154. #define V_SKIN        24
  155.     {"SKIN", V_SKIN, NO_OPTIONS },
  156. #define V_SHIRTCOLOR    25
  157.     {"SHIRTCOLOR", V_SHIRTCOLOR, NO_OPTIONS },
  158. #define V_PANTSCOLOR    26
  159.     {"PANTSCOLOR", V_PANTSCOLOR, NO_OPTIONS },
  160. #define V_PLAYERIP    27
  161.     {"PLAYERIP", V_PLAYERIP, NO_OPTIONS },
  162. #define V_IF    28
  163.     {"IF", V_IF, OPTIONS_OK },
  164. #define V_ENDIF    29
  165.     {"ENDIF", V_ENDIF, NO_OPTIONS },
  166. #define V_HTML    35
  167.     {"HTML", V_HTML, NO_OPTIONS },
  168. #define V_FLAG    36
  169.     {"FLAG", V_FLAG, OPTIONS_OK | EXPR },
  170. #define V_UP    37
  171.     {"UP", V_UP, NO_OPTIONS | EXPR },
  172. #define V_DOWN    38
  173.     {"DOWN", V_DOWN, NO_OPTIONS | EXPR },
  174. #define V_IFNOT    39
  175.     {"IFNOT", V_IFNOT, OPTIONS_OK },
  176. #define V_TIMEOUT    40
  177.     {"TIMEOUT", V_TIMEOUT, NO_OPTIONS | EXPR },
  178. #define V_NOW    41
  179.     {"NOW", V_NOW, NO_OPTIONS },
  180. #define V_TOTALSERVERS    42
  181.     {"TOTALSERVERS", V_TOTALSERVERS, NO_OPTIONS },
  182. #define V_TOTALUP    43
  183.     {"TOTALUP", V_TOTALUP, NO_OPTIONS },
  184. #define V_TOTALNOTUP    44
  185.     {"TOTALNOTUP", V_TOTALNOTUP, NO_OPTIONS },
  186. #define V_TOTALPLAYERS    45
  187.     {"TOTALPLAYERS", V_TOTALPLAYERS, NO_OPTIONS },
  188. #define V_TEAMNUM    49
  189.     {"TEAMNUM", V_TEAMNUM, NO_OPTIONS },
  190. #define V_BACKSLASH    50
  191.     {"\\", V_BACKSLASH, NO_OPTIONS },
  192. #define V_HOSTNOTFOUND    51
  193.     {"HOSTNOTFOUND", V_HOSTNOTFOUND, NO_OPTIONS | EXPR },
  194. #define V_MESH    52
  195.     {"MESH", V_MESH, NO_OPTIONS },
  196. #define V_ISEMPTY    56
  197.     {"ISEMPTY", V_ISEMPTY, NO_OPTIONS | EXPR },
  198. #define V_ISFULL    57
  199.     {"ISFULL", V_ISFULL, NO_OPTIONS | EXPR },
  200. #define V_PACKETLOSS    58
  201.     {"PACKETLOSS", V_PACKETLOSS, NO_OPTIONS },
  202. #define V_ISTEAM    59
  203.     {"ISTEAM", V_ISTEAM, NO_OPTIONS | EXPR },
  204. #define V_TEAMNAME    60
  205.     {"TEAMNAME", V_TEAMNAME, NO_OPTIONS },
  206. #define V_DEFAULTTYPE    61
  207.     {"DEFAULTTYPE", V_DEFAULTTYPE, NO_OPTIONS },
  208. #define V_TYPESTRING    62
  209.     {"TYPESTRING", V_TYPESTRING, NO_OPTIONS },
  210. #define V_FACE        63
  211.     {"FACE", V_FACE, NO_OPTIONS },
  212. #define V_SOLDIEROFFORTUNE        64
  213.     {"SOLDIEROFFORTUNE", V_SOLDIEROFFORTUNE, NO_OPTIONS },
  214. #define V_COLORNUMBERS    65
  215.     {"COLORNUMBERS", V_COLORNUMBERS, NO_OPTIONS },
  216. #define V_COLORNAMES    66
  217.     {"COLORNAMES", V_COLORNAMES, NO_OPTIONS },
  218. #define V_COLORRGB    67
  219.     {"COLORRGB", V_COLORRGB, NO_OPTIONS },
  220. #define V_TIMESECONDS    68
  221.     {"TIMESECONDS", V_TIMESECONDS, NO_OPTIONS },
  222. #define V_TIMECLOCK    69
  223.     {"TIMECLOCK", V_TIMECLOCK, NO_OPTIONS },
  224. #define V_TIMESTOPWATCH    70
  225.     {"TIMESTOPWATCH", V_TIMESTOPWATCH, NO_OPTIONS },
  226. #define V_NOWINT    71
  227.     {"NOWINT", V_NOWINT, NO_OPTIONS },
  228. #define V_ISMASTER    72
  229.     {"ISMASTER", V_ISMASTER, NO_OPTIONS | EXPR },
  230. #define V_HTMLPLAYERNAME    73
  231.     {"HTMLPLAYERNAME", V_HTMLPLAYERNAME, NO_OPTIONS },
  232. #define V_ISBOT    74
  233.     {"ISBOT", V_ISBOT, NO_OPTIONS | EXPR },
  234. #define V_ISALIAS    75
  235.     {"ISALIAS", V_ISALIAS, NO_OPTIONS | EXPR },
  236. #define V_TRIBETAG    76
  237.     {"TRIBETAG", V_TRIBETAG, NO_OPTIONS | EXPR },
  238. #define V_CLEARNEWLINES    77
  239.     {"CLEARNEWLINES", V_CLEARNEWLINES, NO_OPTIONS },
  240. #define V_GAMETYPE    78
  241.     {"GAMETYPE", V_GAMETYPE, NO_OPTIONS },
  242. #define V_DEATHS        79
  243.     {"DEATHS", V_DEATHS, NO_OPTIONS },
  244. #define V_TYPEPREFIX        80
  245.     {"TYPEPREFIX", V_TYPEPREFIX, NO_OPTIONS },
  246. #define V_RULENAMESPACES    81
  247.     {"RULENAMESPACES", V_RULENAMESPACES, NO_OPTIONS },
  248. #define V_RULETEMPLATE        82
  249.     {"RULETEMPLATE", V_RULETEMPLATE, NO_OPTIONS },
  250. #define V_RULENAME        83
  251.     {"RULENAME", V_RULENAME, OPTIONS_OK | EXPR },
  252. #define V_RULEVALUE        84
  253.     {"RULEVALUE", V_RULEVALUE, OPTIONS_OK | EXPR },
  254. };
  255.  
  256. int
  257. read_qserver_template( char *filename)
  258. {
  259.     return read_template( filename, &server_template);
  260. }
  261.  
  262. int
  263. read_rule_template( char *filename)
  264. {
  265.     return read_template( filename, &rule_template);
  266. }
  267.  
  268. int
  269. read_header_template( char *filename)
  270. {
  271.     return read_template( filename, &header_template);
  272. }
  273.  
  274. int
  275. read_trailer_template( char *filename)
  276. {
  277.     return read_template( filename, &trailer_template);
  278. }
  279.  
  280. int
  281. read_player_template( char *filename)
  282. {
  283.     return read_template( filename, &player_template);
  284. }
  285.  
  286. STATIC int
  287. read_template( char *filename, char **template_text)
  288. {
  289.     FILE *file;
  290.     int length, rc;
  291.  
  292.     file= fopen( filename, "r");
  293.     if ( file == NULL)  {
  294.     perror( filename);
  295.     return -1;
  296.     }
  297.  
  298.     fseek( file, 0, SEEK_END);
  299.     length= ftell( file);
  300.     fseek( file, 0, SEEK_SET);
  301.  
  302.     *template_text= (char*)malloc( length+1);
  303.     rc= fread( *template_text, 1, length, file);
  304.     if ( rc == 0 && length > 0)  {
  305.     perror( filename);
  306.     fclose( file);
  307.     free( *template_text);
  308.     *template_text= NULL;
  309.     return -1;
  310.     }
  311.     (*template_text)[rc]= '\0';
  312.     return 0;
  313. }
  314.  
  315. int
  316. have_server_template()
  317. {
  318.     return server_template != NULL;
  319. }
  320.  
  321. int
  322. have_header_template()
  323. {
  324.     return header_template != NULL;
  325. }
  326.  
  327. int
  328. have_trailer_template()
  329. {
  330.     return trailer_template != NULL;
  331. }
  332.  
  333. void
  334. template_display_server( struct qserver *server)
  335. {
  336.     char *t= server_template;
  337.     int var, varlen;
  338.  
  339.     if_level= 0;
  340.     if_skip= 0;
  341.     for ( ; *t; t++)  {
  342.     if ( *t != VARIABLE_CHAR)  {
  343.         if ( ! if_skip)
  344.         putc( *t, OF);
  345.         continue;
  346.     }
  347.     var= parse_var( t, &varlen);
  348.     if ( var == -1)  {
  349.         if ( ! if_skip)
  350.         putc( VARIABLE_CHAR, OF);
  351.         continue;
  352.     }
  353.     if ( var == V_BACKSLASH)  {
  354.         t+= 2;
  355.         if ( *t == '\r')  {
  356.         if ( *++t == '\n')
  357.             t++;
  358.         }
  359.         else if ( *t == '\n')
  360.         t++;
  361.         t--;
  362.         continue;
  363.     }
  364.     if ( (var == V_IF || var == V_IFNOT) && variable_option != NULL)  {
  365.         int truth= (var==V_IF)?1:0;
  366.         if ( !if_skip && is_true( server, NULL, NULL, variable_option) == truth)
  367.         if_level++;
  368.         else
  369.         if_skip++;
  370.     }
  371.     else if ( var == V_ENDIF)  {
  372.         if ( if_skip)
  373.         if_skip--;
  374.         else if ( if_level)
  375.         if_level--;
  376.     }
  377.     if ( ! if_skip)
  378.         display_server_var( server, var);
  379.     t+= varlen;
  380.     }
  381. }
  382.  
  383. void
  384. template_display_players( struct qserver *server)
  385. {
  386.     struct player *player;
  387.     for ( player= server->players; player != NULL; player= player->next)
  388.     template_display_player( server, player);
  389. }
  390.  
  391. void
  392. template_display_player( struct qserver *server, struct player *player)
  393. {
  394.     char *t= player_template;
  395.     int var, varlen;
  396.  
  397.     if ( player_template == NULL)
  398.     return;
  399.  
  400.     if_level= 0;
  401.     if_skip= 0;
  402.     for ( ; *t; t++)  {
  403.     if ( *t != VARIABLE_CHAR)  {
  404.         if ( ! if_skip)
  405.         putc( *t, OF);
  406.         continue;
  407.     }
  408.     var= parse_var( t, &varlen);
  409.     if ( var == -1)  {
  410.         if ( ! if_skip)
  411.         putc( VARIABLE_CHAR, OF);
  412.         continue;
  413.     }
  414.     if ( var == V_BACKSLASH)  {
  415.         t+= 2;
  416.         if ( *t == '\r')  {
  417.         if ( *++t == '\n')
  418.             t++;
  419.         }
  420.         else if ( *t == '\n')
  421.         t++;
  422.         t--;
  423.         continue;
  424.     }
  425.     if ( (var == V_IF || var == V_IFNOT) && variable_option != NULL)  {
  426.         int truth= (var==V_IF)?1:0;
  427.         if ( !if_skip && is_true( server, player, NULL, variable_option) == truth)
  428.         if_level++;
  429.         else
  430.         if_skip++;
  431.     }
  432.     else if ( var == V_ENDIF)  {
  433.         if ( if_skip)
  434.         if_skip--;
  435.         else if ( if_level)
  436.         if_level--;
  437.     }
  438.     if ( ! if_skip)
  439.         display_player_var( player, var, server);
  440.     t+= varlen;
  441.     }
  442. }
  443.  
  444. void
  445. template_display_rules( struct qserver *server)
  446. {
  447.     struct rule *rule;
  448.     for ( rule= server->rules; rule != NULL; rule= rule->next)
  449.     template_display_rule( server, rule);
  450. }
  451.  
  452. void
  453. template_display_rule( struct qserver *server, struct rule *rule)
  454. {
  455.     char *t= rule_template;
  456.     int var, varlen;
  457.  
  458.     if ( rule_template == NULL)
  459.     return;
  460.  
  461.     if_level= 0;
  462.     if_skip= 0;
  463.     for ( ; *t; t++)  {
  464.     if ( *t != VARIABLE_CHAR)  {
  465.         if ( ! if_skip)
  466.         putc( *t, OF);
  467.         continue;
  468.     }
  469.     var= parse_var( t, &varlen);
  470.     if ( var == -1)  {
  471.         if ( ! if_skip)
  472.         putc( VARIABLE_CHAR, OF);
  473.         continue;
  474.     }
  475.     if ( var == V_BACKSLASH)  {
  476.         t+= 2;
  477.         if ( *t == '\r')  {
  478.         if ( *++t == '\n')
  479.             t++;
  480.         }
  481.         else if ( *t == '\n')
  482.         t++;
  483.         t--;
  484.         continue;
  485.     }
  486.     if ( (var == V_IF || var == V_IFNOT) && variable_option != NULL)  {
  487.         int truth= (var==V_IF)?1:0;
  488.         if ( !if_skip && is_true( server, NULL, rule, variable_option) == truth)
  489.         if_level++;
  490.         else
  491.         if_skip++;
  492.     }
  493.     else if ( var == V_ENDIF)  {
  494.         if ( if_skip)
  495.         if_skip--;
  496.         else if ( if_level)
  497.         if_level--;
  498.     }
  499.     if ( ! if_skip)
  500.         display_rule_var( rule, var, server);
  501.     t+= varlen;
  502.     }
  503. }
  504.  
  505. void
  506. template_display_header()
  507. {
  508.     char *t= header_template;
  509.     int var, varlen;
  510.  
  511.     if_level= 0;
  512.     if_skip= 0;
  513.     for ( ; *t; t++)  {
  514.     if ( *t != VARIABLE_CHAR)  {
  515.         putc( *t, OF);
  516.         continue;
  517.     }
  518.     var= parse_var( t, &varlen);
  519.     if ( var == -1)  {
  520.         putc( VARIABLE_CHAR, OF);
  521.         continue;
  522.     }
  523.     if ( var == V_BACKSLASH)  {
  524.         t+= 2;
  525.         if ( *t == '\r')  {
  526.         if ( *++t == '\n')
  527.             t++;
  528.         }
  529.         else if ( *t == '\n')
  530.         t++;
  531.         t--;
  532.         continue;
  533.     }
  534.     display_generic_var( var);
  535.     t+= varlen;
  536.     }
  537. }
  538.  
  539. void
  540. template_display_trailer()
  541. {
  542.     char *t= trailer_template;
  543.     int var, varlen;
  544.  
  545.     if_level= 0;
  546.     if_skip= 0;
  547.     for ( ; *t; t++)  {
  548.     if ( *t != VARIABLE_CHAR)  {
  549.         putc( *t, OF);
  550.         continue;
  551.     }
  552.     var= parse_var( t, &varlen);
  553.     if ( var == -1)  {
  554.         putc( VARIABLE_CHAR, OF);
  555.         continue;
  556.     }
  557.     if ( var == V_BACKSLASH)  {
  558.         t+= 2;
  559.         if ( *t == '\r')  {
  560.         if ( *++t == '\n')
  561.             t++;
  562.         }
  563.         else if ( *t == '\n')
  564.         t++;
  565.         t--;
  566.         continue;
  567.     }
  568.     display_generic_var( var);
  569.     t+= varlen;
  570.     }
  571. }
  572.  
  573. STATIC void
  574. display_server_var( struct qserver *server, int var)
  575. {
  576.     char *game;
  577.     int full_data= 1;
  578.     if ( server->server_name == DOWN || server->server_name == TIMEOUT ||
  579.         server->server_name == SYSERROR || 
  580.         server->error != NULL || server->type->master)
  581.     full_data= 0;
  582.  
  583.     switch( var)  {
  584.     case V_HOSTNAME:
  585.     fputs( (hostname_lookup) ? server->host_name : server->arg, OF);
  586.     break;
  587.     case V_SERVERNAME:
  588.     fputs( xform_name( server->server_name, server), OF);
  589.     break;
  590.     case V_PING:
  591.     if ( server->server_name != TIMEOUT && server->server_name != DOWN &&
  592.         server->server_name != HOSTNOTFOUND)
  593.         fprintf( OF, "%d", server->ping_total/server->n_requests);
  594.     break;
  595.     case V_PLAYERS:
  596.     if ( full_data)
  597.         fprintf( OF, "%d", server->num_players);
  598.     break;
  599.     case V_MAXPLAYERS:
  600.     if ( full_data)
  601.         fprintf( OF, "%d", server->max_players);
  602.     break;
  603.     case V_MAP:
  604.     if ( full_data)
  605.         fputs( (server->map_name) ? server->map_name : "?", OF);
  606.     break;
  607.     case V_GAME:
  608.     if ( full_data)  {
  609.         game= get_qw_game( server);
  610.         fputs( (game) ? game : "", OF);
  611.     }
  612.     break;
  613.     case V_GAMETYPE:
  614.     {
  615.     struct rule *rule;
  616.     for ( rule= server->rules; rule != NULL; rule= rule->next)
  617.         if ( strcasecmp( rule->name, "g_gametype") == 0)
  618.         break;
  619.     if ( rule != NULL)  {
  620.         switch ( atoi(rule->value))  {
  621.         case 0: fputs( "Free For All", OF); break;
  622.         case 1: fputs( "Tournament", OF); break;
  623.         case 3: fputs( "Team Deathmatch", OF); break;
  624.         case 4: fputs( "Capture the Flag", OF); break;
  625.         case 5: fputs( "Fortress or OSP", OF); break;
  626.         case 6: fputs( "Capture and Hold", OF); break;
  627.         case 8: fputs( "Arena", OF); break;
  628.         default: fputs( "?", OF); break;
  629.         }
  630.     }
  631.     }
  632.     break;
  633.     case V_RETRIES:
  634.     if ( server->server_name != TIMEOUT && server->server_name != DOWN &&
  635.         server->server_name != HOSTNOTFOUND)
  636.         fprintf( OF, "%d", server->n_retries);
  637.     break;
  638.     case V_IPADDR:
  639.     { unsigned int ipaddr= ntohl(server->ipaddr);
  640.     fprintf( OF, "%u.%u.%u.%u", (ipaddr>>24)&0xff,
  641.         (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff);
  642.     }
  643.     break;
  644.     case V_PORT:
  645.     fprintf( OF, "%hu", server->port);
  646.     break;
  647.     case V_ARG:
  648.     fputs( server->arg, OF);
  649.     break;
  650.     case V_TYPE:
  651.     fputs( server->type->game_name, OF);
  652.     break;
  653.     case V_TYPESTRING:
  654.     fputs( server->type->type_string, OF);
  655.     break;
  656.     case V_TYPEPREFIX:
  657.     fputs( server->type->type_prefix, OF);
  658.     break;
  659.     case V_RULE:
  660.     {
  661.     struct rule *rule;
  662.     if ( variable_option == NULL)
  663.         break;
  664.     for ( rule= server->rules; rule != NULL; rule= rule->next)
  665.         if ( strcasecmp( rule->name, variable_option) == 0)
  666.         display_string( rule->value);
  667.     }
  668.     break;
  669.     case V_ALLRULES:
  670.     {
  671.     struct rule *rule;
  672.     for ( rule= server->rules; rule != NULL; rule= rule->next)  {
  673.         if ( rule != server->rules)
  674.         fputs( ", ", OF);
  675.         display_string( rule->name);
  676.         putc( '=', OF);
  677.         display_string( rule->value);
  678.     }
  679.     }
  680.     break;
  681.     case V_PLAYERTEMPLATE:
  682.     if_level_save= if_level;
  683.     if_skip_save= if_skip;
  684.     template_display_players( server);
  685.     if_level= if_level_save;
  686.     if_skip= if_skip_save;
  687.     break;
  688.     case V_RULETEMPLATE:
  689.     if_level_save= if_level;
  690.     if_skip_save= if_skip;
  691.     template_display_rules( server);
  692.     if_level= if_level_save;
  693.     if_skip= if_skip_save;
  694.     break;
  695.     default:
  696.     display_generic_var( var);
  697.     }
  698. }
  699.  
  700. STATIC void
  701. display_player_var( struct player *player, int var, struct qserver *server)
  702. {
  703.     switch( var)  {
  704.     case V_PLAYERNAME:
  705.     fputs( xform_name( player->name, server), OF);
  706.     break;
  707.     case V_HTMLPLAYERNAME:  {
  708.     int save_html_names= html_names;
  709.     int save_hex_player_names= hex_player_names;
  710.     html_names= 1;
  711.     hex_player_names= 0;
  712.     fputs( xform_name( player->name, server), OF);
  713.     html_names= save_html_names;
  714.     hex_player_names= save_hex_player_names;
  715.     }
  716.     break;
  717.     case V_TRIBETAG:
  718.     fputs( xform_name( player->tribe_tag, server), OF);
  719.     break;
  720.     case V_FRAGS:
  721.     fprintf( OF, "%d", player->frags);
  722.     break;
  723.     case V_DEATHS:
  724.     fprintf( OF, "%d", player->deaths);
  725.     break;
  726.     case V_PLAYERPING:
  727.     fprintf( OF, "%d", player->ping);
  728.     break;
  729.     case V_CONNECTTIME:
  730.     fputs( play_time(player->connect_time,0), OF);
  731.     break;
  732.     case V_SKIN:
  733.     display_string( player->skin);
  734.     break;
  735.     case V_MESH:
  736.     display_string( player->mesh);
  737.     break;
  738.     case V_FACE:
  739.     display_string( player->face);
  740.     break;
  741.     case V_SHIRTCOLOR:
  742.     if ( color_names)
  743.         fputs( quake_color(player->shirt_color), OF);
  744.     else
  745.         fprintf( OF, "%d", player->shirt_color);
  746.     break;
  747.     case V_PANTSCOLOR:
  748.     if ( color_names)
  749.         fputs( quake_color(player->pants_color), OF);
  750.     else
  751.         fprintf( OF, "%d", player->pants_color);
  752.     break;
  753.     case V_PLAYERIP:
  754.     if ( player->address)
  755.         fputs( player->address, OF);
  756.     break;
  757.     case V_TEAMNUM:
  758.     fprintf( OF, "%d", player->team);
  759.     break;
  760.     case V_PACKETLOSS:
  761.     fprintf( OF, "%d", player->packet_loss);
  762.     break;
  763.     case V_TEAMNAME:
  764.     if ( player->team_name)
  765.         fprintf( OF, "%s", player->team_name);
  766.     break;
  767.     case V_COLORNUMBERS:
  768.     color_names= 0;
  769.     break;
  770.     case V_COLORNAMES:
  771.     color_names= 1;
  772.     break;
  773.     case V_COLORRGB:
  774.     color_names= 2;
  775.     break;
  776.     case V_TIMESECONDS:
  777.     time_format= SECONDS;
  778.     break;
  779.     case V_TIMECLOCK:
  780.     time_format= CLOCK_TIME;
  781.     break;
  782.     case V_TIMESTOPWATCH:
  783.     time_format= STOPWATCH_TIME;
  784.     break;
  785.     default:
  786.     display_server_var( server, var);
  787.     }
  788. }
  789.  
  790. STATIC void
  791. display_rule_var( struct rule *rule, int var, struct qserver *server)
  792. {
  793.     switch( var)  {
  794.     case V_RULENAME:
  795.     fputs( rule->name, OF);
  796.     break;
  797.     case V_RULEVALUE:
  798.     fputs( xform_name( rule->value, server), OF);
  799.     break;
  800.     default:
  801.     display_server_var( server, var);
  802.     }
  803. }
  804.  
  805. STATIC void
  806. display_generic_var( int var)
  807. {
  808.     switch( var)  {
  809.     case V_QSTATURL:
  810.     fputs( "http://www.qstat.org", OF);
  811.     break;
  812.     case V_QSTATVERSION:
  813.     fputs( qstat_version, OF);
  814.     break;
  815.     case V_QSTATAUTHOR:
  816.     fputs( "Steve Jankowski", OF);
  817.     break;
  818.     case V_QSTATAUTHOREMAIL:
  819.     fputs( "steve@qstat.org", OF);
  820.     break;
  821.     case V_HTML:
  822.     html_mode^= 1;
  823.     if ( html_mode && html_names == -1)
  824.         html_names= 1;
  825.     break;
  826.     case V_CLEARNEWLINES:
  827.     clear_newlines_mode^= 1;
  828.     break;
  829.     case V_NOW:  {
  830.     time_t now= time(0);
  831.     char *now_string= ctime(&now);
  832.     now_string[strlen(now_string)-1]= '\0';
  833.     fputs( now_string, OF);
  834.     break;
  835.     }
  836.     case V_NOWINT:
  837.     fprintf( OF, "%u", (unsigned int)time(0));
  838.     break;
  839.     case V_TOTALSERVERS:
  840.     fprintf( OF, "%d", num_servers_total);
  841.     break;
  842.     case V_TOTALUP:
  843.     fprintf( OF, "%d", num_servers_total - num_servers_timed_out -
  844.         num_servers_down);
  845.     break;
  846.     case V_TOTALNOTUP:
  847.     fprintf( OF, "%d", num_servers_timed_out + num_servers_down);
  848.     break;
  849.     case V_TOTALPLAYERS:
  850.     fprintf( OF, "%d", num_players_total);
  851.     break;
  852.     case V_DEFAULTTYPE:
  853.     fprintf( OF, "%s", default_server_type->game_name);
  854.     break;
  855.     case V_RULENAMESPACES:
  856.     rule_name_spaces^= 1;
  857.     break;
  858.     default: break;
  859.     }
  860. }
  861.  
  862. STATIC int
  863. parse_var( char *varname, int *varlen)
  864. {
  865.     char *v= ++varname, *colon= NULL;
  866.     int i, quote= 0;
  867.  
  868.     if ( variable_option != NULL)  {
  869.     free( variable_option);
  870.     variable_option= NULL;
  871.     }
  872.  
  873.     if ( *v == '(')  {
  874.     v++;
  875.     varname++;
  876.     quote++;
  877.     }
  878.     else if ( *v == '\\')  {
  879.     *varlen= 1;
  880.     return V_BACKSLASH;
  881.     }
  882.  
  883.     for ( ; *v; v++)
  884.     if ( (!quote && !isalpha( *v)) || (quote && (*v == ')' || *v == ':')))
  885.         break;
  886.     if ( v-varname == 0)
  887.     return -1;
  888.  
  889.     *varlen= v-varname;
  890.     if ( *v == ':')
  891.     colon= v;
  892.     else if ( quote && *v == ')')
  893.     v++;
  894.  
  895.     for ( i= 0; i < sizeof(variable_defs)/sizeof(struct vardef); i++)
  896.     if ( strncasecmp( varname, variable_defs[i].var, *varlen) == 0 &&
  897.         *varlen == strlen(variable_defs[i].var))  {
  898.         if ( colon != NULL && ((variable_defs[i].options & OPTIONS_OK) || quote))  {
  899.         for ( v++; *v; v++)  {
  900.             if ( (!quote && !isalnum( *v) && *v != '*' && *v != '_' && *v != '.' && (*v == ' ' && !rule_name_spaces)) ||
  901.             (quote==1 && *v == ')')) break;
  902.             if ( *v == '(')
  903.             quote++;
  904.             else if ( *v == ')')
  905.             quote--;
  906.         }
  907.         variable_option= (char*)malloc( v-colon+1);
  908.         strncpy( variable_option, colon+1, v-colon-1);
  909.         variable_option[v-colon-1]= '\0';
  910.         if ( quote && *v == ')')
  911.             v++;
  912.         }
  913.         *varlen= v-varname+quote;
  914.         return variable_defs[i].varcode;
  915.     }
  916.  
  917.     return -1;
  918. }
  919.  
  920. STATIC int
  921. is_true( struct qserver *server, struct player *player, struct rule *rule,
  922.     char *expr)
  923. {
  924.     int i, len, arglen;
  925.     char *arg= NULL, *lparen, *rparen;
  926.     server_type *t;
  927.  
  928.     if ( (lparen= strchr( expr, '(')) != NULL)  {
  929.     if ( (rparen= strchr( lparen, ')')) != NULL)  {
  930.         len= lparen - expr;
  931.         arg= lparen + 1;
  932.         arglen= rparen - lparen - 1;
  933.     }
  934.     }
  935.     else
  936.     len= strlen( expr);
  937.  
  938.     for ( i= 0; i < sizeof(variable_defs)/sizeof(struct vardef); i++)
  939.     if ( strncasecmp( expr, variable_defs[i].var, len) == 0 &&
  940.         len == strlen( variable_defs[i].var))  {
  941.         if ( !(variable_defs[i].options & EXPR))  {
  942.         fprintf( stderr, "unsupported IF expression \"%s\"\n", expr);
  943.         return 1;
  944.         }
  945.         switch ( variable_defs[i].varcode)  {
  946.         case V_GAME:  {
  947.         char *g= get_qw_game( server);
  948.         if ( g == NULL || *g == '\0')
  949.             return 0;
  950.         else
  951.             return 1;
  952.         }
  953.         case V_PLAYERS: return server->num_players > 0;
  954.         case V_ISEMPTY: return server->num_players == 0;
  955.         case V_ISFULL: return server->max_players ? server->num_players >= server->max_players : 0;
  956.         case V_ISTEAM: return player ? player->number == TRIBES_TEAM : 0;
  957.         case V_ISBOT: return player ? player->type_flag == PLAYER_TYPE_BOT : 0;
  958.         case V_ISALIAS: return player ? player->type_flag == PLAYER_TYPE_ALIAS : 0;
  959.         case V_TRIBETAG: return player ? player->tribe_tag != NULL : 0;
  960.         case V_RULE:  {
  961.         struct rule *rule;
  962.         if ( arg == NULL)
  963.             return 0;
  964.         for ( rule= server->rules; rule != NULL; rule= rule->next)
  965.             if ( strncasecmp( rule->name, arg, arglen) == 0 &&
  966.                 strlen( rule->name) == arglen)
  967.             return 1;
  968.         return 0;
  969.         }
  970.         case V_RULENAME:  {
  971.         if ( rule && arg && strncmp( rule->name, arg, arglen) == 0 &&
  972.             strlen( rule->name) == arglen)
  973.             return 1;
  974.         else
  975.             return 0;
  976.         }
  977.         case V_RULEVALUE:  {
  978.         if ( rule && arg && strncmp( rule->value, arg, arglen) == 0 &&
  979.             strlen( rule->value) == arglen)
  980.             return 1;
  981.         else
  982.             return 0;
  983.         }
  984.         case V_FLAG:  {
  985.         if ( strncmp( "-H", arg, arglen) == 0)
  986.             return hostname_lookup;
  987.         if ( strncmp( "-P", arg, arglen) == 0)
  988.             return get_player_info;
  989.         if ( strncmp( "-R", arg, arglen) == 0)
  990.             return get_server_rules;
  991.         return 0;
  992.         }
  993.         case V_UP:
  994.         return server->server_name != DOWN &&
  995.             server->server_name != TIMEOUT &&
  996.             server->server_name != HOSTNOTFOUND;
  997.         case V_DOWN:
  998.         return server->server_name == DOWN;
  999.         case V_TIMEOUT:
  1000.         return server->server_name == TIMEOUT;
  1001.         case V_HOSTNOTFOUND:
  1002.         return server->server_name == HOSTNOTFOUND;
  1003.         case V_ISMASTER:
  1004.         return (server->type->id & MASTER_SERVER) ? 1 : 0;
  1005.         default: return 0;
  1006.         }
  1007.     }
  1008.  
  1009.     t= &types[0];
  1010.     for ( ; t->id; t++)
  1011.     if ( strncasecmp( expr, t->template_var, len) == 0)
  1012.         return server->type->id == t->id;
  1013.  
  1014.     fprintf( stderr, "bad IF expression \"%s\"\n", expr);
  1015.     return 0;
  1016. }
  1017.  
  1018. STATIC void
  1019. display_string( char *str)
  1020. {
  1021.     if ( str == NULL)
  1022.     return;
  1023.     if ( ! html_mode && ! clear_newlines_mode)  {
  1024.     fputs( str, OF);
  1025.     return;
  1026.     }
  1027.  
  1028.     if ( html_mode && ! clear_newlines_mode)  {
  1029.     for ( ; *str; str++)
  1030.     switch ( *str) {
  1031.     case '<': fputs( "<", OF); break;
  1032.     case '>': fputs( ">", OF); break;
  1033.     case '&': fputs( "&", OF); break;
  1034.     case '\n': fputs( "NEWLINE", OF);
  1035.     default: putc( *str, OF);
  1036.     }
  1037.     return;
  1038.     }
  1039.  
  1040.     if ( ! html_mode && clear_newlines_mode)  {
  1041.     for ( ; *str; str++)
  1042.     switch ( *str) {
  1043.     case '\n':
  1044.     case '\r': putc( ' ', OF); break;
  1045.     default: putc( *str, OF);
  1046.     }
  1047.     return;
  1048.     }
  1049.  
  1050.     for ( ; *str; str++)
  1051.     switch ( *str) {
  1052.     case '<': fputs( "<", OF); break;
  1053.     case '>': fputs( ">", OF); break;
  1054.     case '&': fputs( "&", OF); break;
  1055.     case '\n':
  1056.     case '\r': putc( ' ', OF); break;
  1057.     default: putc( *str, OF);
  1058.     }
  1059. }
  1060.  
  1061.